package com.bjut.vendormgrsys.support.filter.jwt;

import com.bjut.vendormgrsys.config.RsaKeyProperties;
import com.bjut.vendormgrsys.model.domain.TokenPO;
import com.bjut.vendormgrsys.service.UserService;
import com.bjut.vendormgrsys.support.bo.UserBO;
import com.bjut.vendormgrsys.util.JsonUtils;
import com.bjut.vendormgrsys.util.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Slf4j
public class JwtLoginFilter extends UsernamePasswordAuthenticationFilter implements IJwtFilter {

    private final AuthenticationManager authenticationManager;
    private final RsaKeyProperties rsaKeyProperties;
    private final UserService userService;
    private final int expire;

    public JwtLoginFilter(AuthenticationManager authenticationManager, RsaKeyProperties rsaKeyProperties,
                          UserService userService, int expire) {
        this.authenticationManager = authenticationManager;
        this.rsaKeyProperties = rsaKeyProperties;
        this.userService = userService;
        this.expire = expire;
    }

    /**
     * 这个方法是用来去尝试验证用户的，父类中是从POST请求的form表单中获取，但是这里不是，所以需要重写
     */
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        try {
            UserBO userBO = JsonUtils.toBean(request.getInputStream(), UserBO.class);
            if (userBO == null) {
                log.error("用户登录异常！");
                response(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "服务内部异常，请联系管理员！", null);
                return null;
            } else {
                return authenticationManager.authenticate(
                        new UsernamePasswordAuthenticationToken(userBO, userBO.getPassword())
                );
            }
        } catch (DisabledException e) {
            log.error("账号不存在：", e);
            response(response, HttpServletResponse.SC_UNAUTHORIZED, "账号不存在！", null);
        } catch (InternalAuthenticationServiceException e) {
            log.error("用户登录异常：", e);
            response(response, HttpServletResponse.SC_UNAUTHORIZED, "账号不存在！", null);
        } catch (AuthenticationException e) {
            log.error("用户登录异常：", e);
            response(response, HttpServletResponse.SC_UNAUTHORIZED, "账号或密码错误！", null);
        } catch (Exception e) {
            log.error("用户登录异常：", e);
            response(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "服务内部异常，请联系管理员！", null);
        }
        return null;
    }

    /**
     * 成功之后执行的方法，父类中是放入session，不符合我们的要求，所以重写
     */
    @Transactional
    @Override
    public void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) {
        UserBO userBO = (UserBO) authResult.getPrincipal();
        String token = JwtUtils.generateTokenExpireInMinutes(userBO, rsaKeyProperties.getPrivateKey(), expire);
        String account = userBO.getAccount();
        TokenPO oldToken = userService.getTokenPOByAccount(account);
        if (oldToken != null) {
            userService.deleteTokenPOById(oldToken.getId());
        }
        TokenPO tokenPO = new TokenPO(account, token);
        userService.insertTokenPO(tokenPO);
        String id = tokenPO.getId();
        response(response, HttpServletResponse.SC_OK, "登陆成功！", id);
    }
}
